#!/usr/bin/env python
# coding: utf-8

# # 自定义数据集
# [luojianet.dataset](http://58.48.42.237/luojiaNet/luojiaNetapi/)提供了部分常用数据集和标准格式数据集的加载接口。对于luojianet暂不支持直接加载的数据集，可以通过构造自定义数据集类或自定义数据集生成函数的方式来生成数据集，然后通过[luojianet.dataset.GeneratorDataset](http://58.48.42.237/luojiaNet/luojiaNetapi/#luojianet.dataset.GeneratorDataset)接口实现自定义方式的数据集加载。
# 
# 通过**自定义数据集类**和**自定义数据集**生成函数两种方式生成的数据集，都可以完成加载、迭代等操作。由于在自定义数据集类中定义了随机访问函数和获取数据集大小函数，因此当需要随机访问数据集中某条数据或获取数据集大小时，使用自定义数据集类生成的数据集可以快速完成这些操作，而通过自定义数据集生成函数的方式生成的数据集需要对数据逐条遍历方可完成这些操作。
# 
# 一般情况下，当数据量较小时使用两种生成自定义数据集的方式中的任一种都可以，而当数据量过大时，优先使用自定义数据集类的方式生成数据集。
# 
# 本篇我们分别介绍**自定义数据集类**和**自定义数据集**两种生成自定义数据集的方式。
# 
# ## 自定义数据集类
# 
# 在用户自定义数据集类中须要自定义的类函数如下：
# 
# - `__init__`：定义数据初始化等操作，在实例化数据集对象时被调用。
# - `__getitem__`：定义该函数后可使其支持随机访问，能够根据给定的索引值`index`，获取数据集中的数据并返回。数据返回值类型是由NumPy数组组成的Tuple。
# - `__len__`：返回数据集的样本数量。
# 
# 在完成自定义数据集类之后，可以通过`GeneratorDataset`接口按照用户定义的方式加载并访问数据集样本。下面我们通过两段示例代码来说明使用自定义数据集类的方式生成单标签数据集和多标签数据集的方法。
# 
# ### 生成单标签数据集
# 
# 通过自定义数据集类`MyDataset`生成五组数据，每组数据由两个随机数组成且只有一个标签。示例代码如下：

# In[14]:


import numpy as np
import luojianet.dataset as ds

np.random.seed(1)

class MyDataset:
    """自定义数据集类"""

    def __init__(self):
        """自定义初始化操作"""
        self.data = np.random.sample((5, 2))  # 自定义数据
        self.label = np.random.sample((5, 1))  # 自定义标签

    def __getitem__(self, index):
        """自定义随机访问函数"""
        return self.data[index], self.label[index]

    def __len__(self):
        """自定义获取样本数据量函数"""
        return len(self.data)

# 实例化数据集类
dataset_generator = MyDataset()
dataset = ds.GeneratorDataset(dataset_generator, ["data", "label"], shuffle=False)

# 迭代访问数据集
for data in dataset.create_dict_iterator():
    data1 = data['data'].asnumpy()
    label1 = data['label'].asnumpy()
    print(f'data:[{data1[0]:7.5f}, {data1[1]:7.5f}], label:[{label1[0]:7.5f}]')

# 打印数据条数
print("data size:", dataset.get_dataset_size())


# 从上面的打印可以看出，通过自定义数据集类生成的数据集一共有五组，每组数据有一个标签。
# 
# ### 生成多标签数据集
# 
# 通过自定义数据集类`MyDataset`生成五组数据，每组数据由两个随机数组成且有两个标签`label1`和`lable2`。示例代码如下：

# In[2高级数据集管理]:


import numpy as np
import luojianet.dataset as ds

np.random.seed(1)

class MyDataset:
    """自定义数据集类"""
    def __init__(self):
        """自定义初始化操作"""
        self.data = np.random.sample((5, 2))  # 自定义数据
        self.label1 = np.random.sample((5, 1))  # 自定义标签1
        self.label2 = np.random.sample((5, 1))  # 自定义标签2

    def __getitem__(self, index):
        """自定义随机访问函数"""
        return self.data[index], self.label1[index], self.label2[index]

    def __len__(self):
        """自定义获取样本数据量函数"""
        return len(self.data)

# 实例化数据集类
dataset_generator = MyDataset()
# 加载数据集
dataset = ds.GeneratorDataset(dataset_generator, ["data", "label1", "label2"], shuffle=False)

# 迭代访问数据集
for data in dataset.create_dict_iterator():
    print("data:[{:7.5f},".format(data['data'].asnumpy()[0]),
          "{:7.5f}]  ".format(data['data'].asnumpy()[1]),
          "label1:[{:7.5f}]".format(data['label1'].asnumpy()[0]),
          "label2:[{:7.5f}]".format(data['label2'].asnumpy()[0]))

# 打印数据条数
print("data size:", dataset.get_dataset_size())


# 从上面的打印可以看出，通过自定义数据集类生成的数据集一共有五组，每组数据有两个标签。
# 
# ## 自定义数据集生成函数
# 
# 我们也可以通过使用自定义数据集生成函数的方式生成数据集，之后使用`GeneratorDataset`接口按照用户定义的方式加载并访问数据集样本。
# 
# 下面我们通过两段示例代码来说明如何使用自定义数据集生成函数的方式来分别生成单标签数据集和多标签数据集。
# 
# ### 生成单标签数据集
# 
# 通过自定义数据集生成函数`get_singlelabel_data`生成五组数据，每组数据由一个随机数组成且只有一个标签。示例代码如下：

# In[3图像处理]:


import numpy as np
from luojianet import dataset as ds

def get_singlelabel_data(num):
    """定义生成单标签数据集函数"""
    for _ in range(num):
        data = np.random.uniform(-10.0, 10.0)  # 自定义数据
        label = np.random.uniform(-1.0, 1.0)  # 自定义标签
        yield np.array([data]).astype(np.float32), np.array([label]).astype(np.float32)

# 定义数据集
dataset = ds.GeneratorDataset(list(get_singlelabel_data(5)), column_names=['data', 'label'])

# 打印数据集
for data in dataset.create_dict_iterator():
    print("data:[{:9.5f}]  ".format(data['data'].asnumpy()[0]),
          "label:[{:9.5f}]  ".format(data['label'].asnumpy()[0]))

# 打印数据条数
print("data size:", dataset.get_dataset_size())


# 从上面的打印可以看出，通过自定义数据集生成函数`get_singlelabel_data`生成的数据集一共有五组，每组数据只有一个标签。
# 
# ### 生成多标签数据集
# 
# 下面我们通过自定义数据集生成函数`get_multilabel_data`来生成一个多标签数据集，每组数据由一个随机数组成且有两个标签。
# 
# 示例代码如下：

# In[4自然语言]:


import numpy as np
from luojianet import dataset as ds

def get_multilabel_data(num, w=2.0, b=3.0):
    """定义生成多标签数据集函数"""
    for _ in range(num):
        data = np.random.uniform(-10.0, 10.0)  # 自定义数据
        label1 = np.random.uniform(-1.0, 1.0)  # 自定义标签1
        label2 = np.random.uniform(1.0, 2.0)  # 自定义标签2
        yield np.array([data]).astype(np.float32), np.array([label1]).astype(np.float32), np.array([label2]).astype(np.float32)

# 定义数据集
dataset = ds.GeneratorDataset(list(get_multilabel_data(5)), column_names=['data', 'label1', 'label2'])

# 打印数据集
for data in dataset.create_dict_iterator():
    print("data:[{:9.5f}]  ".format(data['data'].asnumpy()[0]),
          "label1:[{:9.5f}]  ".format(data['label1'].asnumpy()[0]),
          "label2:[{:9.5f}]".format(data['label2'].asnumpy()[0]))

# 打印数据条数
print("data size:", dataset.get_dataset_size())


# 从上面的打印可以看出，通过自定义数据集生成函数生成的数据集共五组，每组数据有两个标签。
